package com.it.emall.service.impl;

import com.it.emall.domain.Recipes;
import com.it.emall.mapper.RecommendationsMapper;
import com.it.emall.service.RecommendationsService;
import com.it.emall.vo.HealthStatusVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class RecommendationsServiceImpl implements RecommendationsService {

    @Autowired
    private RecommendationsMapper recommendationsMapper;

    @Override
    public List<Recipes> getRecommendations(int userId) {
        System.out.println("进入 getRecommendations 方法，用户 ID: " + userId);

        if (userId == 0) {
            // 用户未登录，返回所有食谱
            System.out.println("用户未登录，返回所有食谱");
            return recommendationsMapper.findAllRecipes();
        }

        // 获取用户的点赞和收藏食谱
        List<Integer> likedRecipes = recommendationsMapper.findLikedRecipeIdsByUserId(userId);
        List<Integer> favoritedRecipes = recommendationsMapper.findFavoritedRecipeIdsByUserId(userId);
        System.out.println("用户 " + userId + " 点赞的食谱数量: " + likedRecipes.size());
        System.out.println("用户 " + userId + " 收藏的食谱数量: " + favoritedRecipes.size());

        // 结合用户互动的食谱ID
        Set<Integer> userInteractedRecipes = new HashSet<>();
        userInteractedRecipes.addAll(likedRecipes);
        userInteractedRecipes.addAll(favoritedRecipes);
        System.out.println("用户 " + userId + " 互动的食谱数量: " + userInteractedRecipes.size());

        // 获取用户健康状况描述
        String healthStatus = recommendationsMapper.findHealthStatusByUserId(userId);
        System.out.println("用户 " + userId + " 的健康状况: " + healthStatus);

        // 解析健康状况并返回对应的营养需求范围
        HealthStatusVo userHealthStatus = parseHealthStatus(healthStatus);
        System.out.println("用户 " + userId + " 的健康状况对应的营养需求范围: " + userHealthStatus);

        if (!userInteractedRecipes.isEmpty()) {
            // 使用协同过滤算法进行推荐
            System.out.println("用户 " + userId + " 有互动数据，使用协同过滤推荐");
            return getCollaborativeFilteringRecommendations(userId, userInteractedRecipes, userHealthStatus);
        }

        // 用户没有点赞、收藏，也没有健康状况 ➝ 随机推荐
        System.out.println("用户没有互动数据或健康状况，进行随机推荐");
        return recommendationsMapper.findRandomRecipes();
    }

    private List<Recipes> getCollaborativeFilteringRecommendations(int userId, Set<Integer> userInteractedRecipes, HealthStatusVo userHealthStatus) {
        System.out.println("进入 getCollaborativeFilteringRecommendations 方法，用户 ID: " + userId);

        Map<Integer, Set<Integer>> allUserInteractions = new HashMap<>();
        List<Integer> allUserIds = recommendationsMapper.findAllUserIds();
        System.out.println("获取所有用户的 ID 数量: " + allUserIds.size());

        for (Integer otherUserId : allUserIds) {
            if (!Objects.equals(otherUserId, userId)) {
                Set<Integer> otherUserInteractions = new HashSet<>(recommendationsMapper.findLikedRecipeIdsByUserId(otherUserId));
                otherUserInteractions.addAll(recommendationsMapper.findFavoritedRecipeIdsByUserId(otherUserId));
                allUserInteractions.put(otherUserId, otherUserInteractions);
                System.out.println("用户 " + otherUserId + " 互动的食谱数量: " + otherUserInteractions.size());
            }
        }

        // 计算相似度
        System.out.println("计算用户与其他用户的相似度...");
        Map<Integer, Double> similarityScores = new HashMap<>();
        for (Map.Entry<Integer, Set<Integer>> entry : allUserInteractions.entrySet()) {
            double similarity = calculateJaccardSimilarity(userInteractedRecipes, entry.getValue());
            similarityScores.put(entry.getKey(), similarity);
            System.out.println("用户 " + entry.getKey() + " 与当前用户的相似度: " + similarity);
        }

        // 获取基于相似度的推荐食谱
        System.out.println("获取基于相似度的推荐食谱...");
        List<Integer> recommendedRecipeIds = similarityScores.entrySet().stream()
                .sorted(Map.Entry.<Integer, Double>comparingByValue().reversed())
                .flatMap(entry -> allUserInteractions.get(entry.getKey()).stream())
                .filter(recipeId -> !userInteractedRecipes.contains(recipeId))
                .distinct()
                .limit(10)
                .collect(Collectors.toList());
        System.out.println("根据相似度推荐的食谱 ID: " + recommendedRecipeIds);

        // 获取符合健康状况的食谱
        System.out.println("根据健康状况筛选食谱...");
        List<Recipes> healthStatusRecipes = recommendationsMapper.findRecipesByNutritionRange(
                userHealthStatus.getMinCalories(),
                userHealthStatus.getMaxCalories(),
                userHealthStatus.getMinProtein(),
                userHealthStatus.getMaxProtein(),
                userHealthStatus.getMinFat(),
                userHealthStatus.getMaxFat(),
                userHealthStatus.getMinCarb(),
                userHealthStatus.getMaxCarb()
        );
        System.out.println("根据健康状况推荐的食谱数量: " + healthStatusRecipes.size());

        // 合并协同过滤推荐与健康状况推荐的食谱
        System.out.println("合并协同过滤推荐和健康状况推荐的食谱...");
        Set<Integer> recommendedSet = new HashSet<>(recommendedRecipeIds);
        Set<Integer> healthSet = healthStatusRecipes.stream().map(Recipes::getId).collect(Collectors.toSet());

        // 去重并合并食谱推荐
        recommendedSet.addAll(healthSet);
        List<Integer> finalRecommendedRecipeIds = new ArrayList<>(recommendedSet);
        System.out.println("最终推荐的食谱 ID: " + finalRecommendedRecipeIds);

        return recommendationsMapper.findRecipesByIds(finalRecommendedRecipeIds);
    }

    private double calculateJaccardSimilarity(Set<Integer> setA, Set<Integer> setB) {
        System.out.println("计算 Jaccard 相似度...");
        Set<Integer> intersection = new HashSet<>(setA);
        intersection.retainAll(setB);
        Set<Integer> union = new HashSet<>(setA);
        union.addAll(setB);
        double similarity = (double) intersection.size() / union.size();
        System.out.println("Jaccard 相似度: " + similarity);
        return similarity;
    }

    private HealthStatusVo parseHealthStatus(String healthStatus) {
        System.out.println("解析健康状况: " + healthStatus);

        // 解析健康状况并返回相应的营养需求范围
        if (healthStatus == null || healthStatus.isEmpty()) {
            System.out.println("健康状况为空，返回默认范围");
            return new HealthStatusVo(1, 99999, 1, 99999, 1, 99999, 1, 99999); // 默认范围
        }
        if (healthStatus.contains("高血压")) {
            System.out.println("健康状况为高血压，返回高血压范围");
            return new HealthStatusVo(1500, 2500, 50, 100, 30, 70, 20, 100); // 高血压范围
        } else if (healthStatus.contains("糖尿病")) {
            System.out.println("健康状况为糖尿病，返回糖尿病范围");
            return new HealthStatusVo(1200, 1800, 60, 90, 20, 60, 10, 60); // 糖尿病范围
        } else if (healthStatus.contains("高胆固醇")) {
            System.out.println("健康状况为高胆固醇，返回高胆固醇范围");
            return new HealthStatusVo(1500, 2300, 60, 100, 25, 70, 30, 100); // 高胆固醇范围
        } else {
            System.out.println("健康状况为其他，返回默认范围");
            return new HealthStatusVo(1, 99999, 1, 99999, 1, 99999, 1, 99999); // 默认范围
        }
    }
}
